/*
 * LoRa.c
 *
 *  Created on: May 30, 2020
 *      Author: admin
 */
#include <stdio.h>
#include "LoRa.h"

LoRaAttr_t* pLoRa_Attributes;

// LoRa hardware driver
uint8_t LoRa_SingleTransfer(uint8_t address, uint8_t value)
{
  uint8_t sendBuffer[2], readBuffer[2];
  sendBuffer[0] = address;
  sendBuffer[1] = value;
  HAL_GPIO_WritePin(LoRa_CS_GPIO_Port, LoRa_CS_Pin, GPIO_PIN_RESET);
  HAL_SPI_TransmitReceive(&hspi1, sendBuffer, readBuffer, 2, HAL_MAX_DELAY);
  HAL_GPIO_WritePin(LoRa_CS_GPIO_Port, LoRa_CS_Pin, GPIO_PIN_SET);
  return readBuffer[1];
}

uint8_t LoRa_ReadRegister(uint8_t address)
{
  return LoRa_SingleTransfer(address & 0x7f, 0x00);
}

void LoRa_WriteRegister(uint8_t address, uint8_t value)
{
  LoRa_SingleTransfer(address | 0x80, value);
}
/**************************************************/


void LoRa_Reset(void)
{
  HAL_GPIO_WritePin(LoRa_RST_GPIO_Port, LoRa_RST_Pin, GPIO_PIN_RESET);
  HAL_Delay(20);
  HAL_GPIO_WritePin(LoRa_RST_GPIO_Port, LoRa_RST_Pin, GPIO_PIN_SET);
  HAL_Delay(50);
}

int LoRa_Init(LoRaAttr_t* LoRaAttr)
{
  pLoRa_Attributes = LoRaAttr;
  LoRa_Reset();
  if(LoRa_ReadRegister(REG_VERSION) != 0x12)
  {
    return -1;
  }
  LoRa_Sleep();
  LoRa_SetFrequency(LoRaAttr->frequency);
  // set base addresses
  LoRa_WriteRegister(REG_FIFO_TX_BASE_ADDR, 0);
  LoRa_WriteRegister(REG_FIFO_RX_BASE_ADDR, 0);
  // set LNA boost
  LoRa_WriteRegister(REG_LNA, LoRa_ReadRegister(REG_LNA) | 0x03);
  // set auto AGC
  LoRa_WriteRegister(REG_MODEM_CONFIG_3, 0x04);
  LoRa_SetTxPower(LoRaAttr->txPower, (LoRaAttr->txPower > 14) ? PA_OUTPUT_PA_BOOST_PIN : PA_OUTPUT_RFO_PIN);
  LoRa_SetSpreadingFactor(LoRaAttr->spreadingFactor);
  LoRa_SetSignalBandwidth(LoRaAttr->signalBandwidth);
  LoRa_SetCodingRate(LoRaAttr->codingRate);
  LoRa_SetSyncWord(LoRaAttr->syncCode);
  LoRa_DisableCrc();
  LoRa_EnableCrc();
  LoRa_Idle();
  return 0;
}


// LoRa software driver
//uint8_t LoRa_init(uint32_t frequency, uint8_t boost)
//{
//  // setup pins
//  // perform reset
//  HAL_GPIO_WritePin(LoRa_RST_GPIO_Port, LoRa_RST_Pin, GPIO_PIN_RESET);
//  HAL_Delay(20);
//  HAL_GPIO_WritePin(LoRa_RST_GPIO_Port, LoRa_RST_Pin, GPIO_PIN_SET);
//  HAL_Delay(50);
//  // check version
//  uint8_t version = LoRa_ReadRegister(REG_VERSION);
//  if (version != 0x12)
//  {
//    return 1;
//  }
//  // put in sleep mode
//  LoRa_Sleep();
//  // set frequency
//  LoRa_SetFrequency(frequency);
//  // set base addresses
//  LoRa_WriteRegister(REG_FIFO_TX_BASE_ADDR, 0);
//  LoRa_WriteRegister(REG_FIFO_RX_BASE_ADDR, 0);
//  // set LNA boost
//  LoRa_WriteRegister(REG_LNA, LoRa_ReadRegister(REG_LNA) | 0x03);
//  // set auto AGC
//  LoRa_WriteRegister(REG_MODEM_CONFIG_3, 0x04);
//  if(boost)
//  {
//  	// set output power to 20 dBm
//    LoRa_SetTxPower(17, PA_OUTPUT_PA_BOOST_PIN);
//  }
//  else
//  {
//    LoRa_SetTxPower(14, PA_OUTPUT_RFO_PIN);
//  }
//  //setTxPowerMax(14);  //PA_BOOST
//  // set Spreading Factor to 7 (6~12)
//  LoRa_SetSpreadingFactor(10);
//  // put in standby mode
//  LoRa_SetSignalBandwidth(125E3);
//  LoRa_SetCodingRate(6);
//  LoRa_SetSyncWord(100);
//  LoRa_DisableCrc();
//  LoRa_EnableCrc();
//  LoRa_Idle();
//  return 0;
//}

void LoRa_LowDataRateOptimize(uint8_t status)
{
  if(status)
  {
    LoRa_WriteRegister(REG_MODEM_CONFIG_3, LoRa_ReadRegister(REG_MODEM_CONFIG_3) | 0x08);
  }
  else
  {
    LoRa_WriteRegister(REG_MODEM_CONFIG_3, LoRa_ReadRegister(REG_MODEM_CONFIG_3) & 0xf7);
  }
}

void LoRa_End()
{
  pLoRa_Attributes = NULL;
  LoRa_Sleep();
}

void LoRa_BeginPacket(uint8_t implicitHeader)
{
  // put in standby mode
  LoRa_Idle();
  if (implicitHeader)
  {
    LoRa_ImplicitHeaderMode();
  } else
  {
    LoRa_ExplicitHeaderMode();
  }
  // reset FIFO address and paload length
  LoRa_WriteRegister(REG_FIFO_ADDR_PTR, 0);
  LoRa_WriteRegister(REG_PAYLOAD_LENGTH, 0);
}

void LoRa_EndPacket()
{
  // put in TX mode
  LoRa_WriteRegister(REG_OP_MODE, MODE_LONG_RANGE_MODE | MODE_TX);
  // wait for TX done
  while((LoRa_ReadRegister(REG_IRQ_FLAGS) & IRQ_TX_DONE_MASK) == 0)
  {
    HAL_Delay(100);
  }
  // clear IRQ's
  LoRa_WriteRegister(REG_IRQ_FLAGS, IRQ_TX_DONE_MASK);
}

uint8_t LoRa_ParsePacket(uint8_t size)
{
  int packetLength = 0;
  int irqFlags = LoRa_ReadRegister(REG_IRQ_FLAGS);

  if (size > 0)
  {
    LoRa_ImplicitHeaderMode();
    LoRa_WriteRegister(REG_PAYLOAD_LENGTH, size & 0xff);
  }
  else
  {
    LoRa_ExplicitHeaderMode();
  }

  // clear IRQ's
  LoRa_WriteRegister(REG_IRQ_FLAGS, irqFlags);

  if ((irqFlags & IRQ_RX_DONE_MASK) && (irqFlags & IRQ_PAYLOAD_CRC_ERROR_MASK) == 0)
  {
    // received a packet
    pLoRa_Attributes->packetIndex = 0;
    // read packet length
    if (pLoRa_Attributes->implicitHeaderMode)
    {
      packetLength = LoRa_ReadRegister(REG_PAYLOAD_LENGTH);
    }
    else
    {
      packetLength = LoRa_ReadRegister(REG_RX_NB_BYTES);
    }
    // set FIFO address to current RX address
    LoRa_WriteRegister(REG_FIFO_ADDR_PTR, LoRa_ReadRegister(REG_FIFO_RX_CURRENT_ADDR));
    // put in standby mode
    LoRa_Idle();
  }
  else if (LoRa_ReadRegister(REG_OP_MODE) != (MODE_LONG_RANGE_MODE | MODE_RX_SINGLE))
  {
    // not currently in RX mode
    // reset FIFO address
    LoRa_WriteRegister(REG_FIFO_ADDR_PTR, 0);
    // put in single RX mode
    LoRa_WriteRegister(REG_OP_MODE, MODE_LONG_RANGE_MODE | MODE_RX_SINGLE);
  }
  return packetLength;
}

uint8_t LoRa_PacketRssi()
{
  return (LoRa_ReadRegister(REG_PKT_RSSI_VALUE) - (pLoRa_Attributes->frequency < 868E6 ? 164 : 157));
}

uint8_t LoRa_PacketSnr()
{
  return LoRa_ReadRegister(REG_PKT_SNR_VALUE) >> 2;
}

uint8_t LoRa_WriteFifoByte(uint8_t data)
{
  int currentLength = LoRa_ReadRegister(REG_PAYLOAD_LENGTH);
  // check size
  if (currentLength == MAX_PKT_LENGTH)
  {
    return 1;
  }
  // write data
  LoRa_WriteRegister(REG_FIFO, data);
  // update length
  LoRa_WriteRegister(REG_PAYLOAD_LENGTH, currentLength + 1);
  return 0;
}

uint8_t LoRa_WriteFifoBytes(const uint8_t *buffer, uint8_t size)
{
  int currentLength = LoRa_ReadRegister(REG_PAYLOAD_LENGTH);
  // check size
  if ((currentLength + size) > MAX_PKT_LENGTH)
  {
    size = MAX_PKT_LENGTH - currentLength;
  }
  // write data
  for (size_t i = 0; i < size; i++)
  {
    LoRa_WriteRegister(REG_FIFO, buffer[i]);
  }
  // update length
  LoRa_WriteRegister(REG_PAYLOAD_LENGTH, currentLength + size);
  return size;
}

uint8_t LoRa_Available()
{
  return (LoRa_ReadRegister(REG_RX_NB_BYTES) - pLoRa_Attributes->packetIndex);
}

uint8_t LoRa_ReadFifo()
{
  if (!LoRa_Available())
  {
    return 0;
  }
  pLoRa_Attributes->packetIndex++;
  return LoRa_ReadRegister(REG_FIFO);
}

uint8_t LoRa_Peek()
{
  if (!LoRa_Available())
  {
    return 0;
  }
  // store current FIFO address
  int currentAddress = LoRa_ReadRegister(REG_FIFO_ADDR_PTR);
  // read
  uint8_t b = LoRa_ReadRegister(REG_FIFO);
  // restore FIFO address
  LoRa_WriteRegister(REG_FIFO_ADDR_PTR, currentAddress);
  return b;
}

//void LoRa_onReceive()  //Don't know the meaning for now
//{
//	LoRa_WriteRegister(REG_DIO_MAPPING_1, 0x00);
//}

void LoRa_Receive(uint8_t size)
{
  LoRa_WriteRegister(REG_DIO_MAPPING_1, 0x00);
  if (size > 0)
  {
    LoRa_ImplicitHeaderMode();
    LoRa_WriteRegister(REG_PAYLOAD_LENGTH, size);
  }
  else
  {
    LoRa_ExplicitHeaderMode();
  }

  LoRa_WriteRegister(REG_OP_MODE, MODE_LONG_RANGE_MODE | MODE_RX_CONTINUOUS);
}

void LoRa_Idle()
{
  LoRa_WriteRegister(REG_OP_MODE, MODE_LONG_RANGE_MODE | MODE_STDBY);
}

void LoRa_Sleep()
{
  LoRa_WriteRegister(REG_OP_MODE, MODE_LONG_RANGE_MODE | MODE_SLEEP);
}

void LoRa_SetTxPower(uint8_t level, uint8_t outputPin)
{
  if (PA_OUTPUT_RFO_PIN == outputPin)
  {
    // RFO
    if (level < -1)
    {
      level = -1;
    }
    else if (level > 14)
    {
      level = 14;
    }
    LoRa_WriteRegister(REG_PaDac,0x84);
    LoRa_WriteRegister(REG_PA_CONFIG, RFO | (level + 1));
  }

  else {			// PA BOOST
    if (level < 2)
    {
      level = 2;
    }
    else if (level > 17)
    {
      level = 17;
    }
    LoRa_WriteRegister(REG_PaDac,0x87);
    LoRa_WriteRegister(REG_PA_CONFIG, PA_BOOST | (level - 2));//LoRa_WriteRegister(REG_PA_CONFIG, PA_BOOST | (level - 2))
  }
}

void LoRa_SetTxPowerMax(uint8_t level)
{
  if (level < 5)
  {
    level = 5;
  }
  else if(level > 20)
  {
    level = 20;
  }
  LoRa_WriteRegister(REG_LR_OCP,0x3f);
  LoRa_WriteRegister(REG_PaDac,0x87);//Open PA_BOOST
  LoRa_WriteRegister(REG_PA_CONFIG, PA_BOOST | (level - 5));
}

void LoRa_SetFrequency(uint32_t frequency)
{
  pLoRa_Attributes->frequency = frequency;
  uint64_t frf = ((uint64_t)frequency << 19) / 32000000;
  LoRa_WriteRegister(REG_FRF_MSB, (uint8_t)(frf >> 16));
  LoRa_WriteRegister(REG_FRF_MID, (uint8_t)(frf >> 8));
  LoRa_WriteRegister(REG_FRF_LSB, (uint8_t)(frf >> 0));
}

void LoRa_SetSpreadingFactor(uint8_t sf)
{
  if (sf < 6)
  {
    sf = 6;
  }
  else if (sf > 12)
  {
    sf = 12;
  }
  if (sf == 6)
  {
    LoRa_WriteRegister(REG_DETECTION_OPTIMIZE, 0xc5);
    LoRa_WriteRegister(REG_DETECTION_THRESHOLD, 0x0c);
  }
  else
  {
    LoRa_WriteRegister(REG_DETECTION_OPTIMIZE, 0xc3);
    LoRa_WriteRegister(REG_DETECTION_THRESHOLD, 0x0a);
  }
  LoRa_WriteRegister(REG_MODEM_CONFIG_2, (LoRa_ReadRegister(REG_MODEM_CONFIG_2) & 0x0f) | ((sf << 4) & 0xf0));
}

void LoRa_SetSignalBandwidth(uint32_t sbw)
{
  uint8_t bw;

  if (sbw <= 7.8E3) { bw = 0; }
  else if (sbw <= 10.4E3)       { bw = 1; }
  else if (sbw <= 15.6E3)       { bw = 2; }
  else if (sbw <= 20.8E3)       { bw = 3; }
  else if (sbw <= 31.25E3)      { bw = 4; }
  else if (sbw <= 41.7E3)       { bw = 5; }
  else if (sbw <= 62.5E3)       { bw = 6; }
  else if (sbw <= 125E3)        { bw = 7; }
  else if (sbw <= 250E3)        { bw = 8; }
  else                          { bw = 9; }
  LoRa_WriteRegister(REG_MODEM_CONFIG_1,(LoRa_ReadRegister(REG_MODEM_CONFIG_1) & 0x0f) | (bw << 4));
}

void LoRa_SetCodingRate(uint8_t denominator)
{
  if (denominator < 5) {
    denominator = 5;
  } else if (denominator > 8) {
    denominator = 8;
  }
  int cr = denominator - 4;
  LoRa_WriteRegister(REG_MODEM_CONFIG_1, (LoRa_ReadRegister(REG_MODEM_CONFIG_1) & 0xf1) | (cr << 1));
}

void LoRa_SetPreambleLength(uint16_t length)
{
  LoRa_WriteRegister(REG_PREAMBLE_MSB, (uint8_t)(length >> 8));
  LoRa_WriteRegister(REG_PREAMBLE_LSB, (uint8_t)(length >> 0));
}

void LoRa_SetSyncWord(uint8_t sw)
{
  LoRa_WriteRegister(REG_SYNC_WORD, sw);
}

void LoRa_EnableCrc()
{
  LoRa_WriteRegister(REG_MODEM_CONFIG_2, LoRa_ReadRegister(REG_MODEM_CONFIG_2) | 0x04);
}

void LoRa_DisableCrc()
{
  LoRa_WriteRegister(REG_MODEM_CONFIG_2, LoRa_ReadRegister(REG_MODEM_CONFIG_2) & 0xfb);
}

uint8_t LoRa_Random()
{
  return LoRa_ReadRegister(REG_RSSI_WIDEBAND);
}

void LoRa_DumpRegisters()
{
  for(uint8_t i=0; i<128; i++)
  {
    printf("0x%02x: 0x%02x", i, LoRa_ReadRegister(i));
  }
}

void LoRa_ExplicitHeaderMode()
{
  pLoRa_Attributes->implicitHeaderMode = 0;
  LoRa_WriteRegister(REG_MODEM_CONFIG_1, LoRa_ReadRegister(REG_MODEM_CONFIG_1) & 0xfe);
}

void LoRa_ImplicitHeaderMode()
{
  pLoRa_Attributes->implicitHeaderMode = 1;
  LoRa_WriteRegister(REG_MODEM_CONFIG_1, LoRa_ReadRegister(REG_MODEM_CONFIG_1) | 0x01);
}
/**************************************************/



// LoRa DIO0 rising edge interrupt callback function (accept interrupt)
__weak void OnReceiveCallback(uint8_t packetLength)
{
  printf("onReceiveCallback run packetLength:%d\n", packetLength);
}

void LoRa_HandleDio0Rise()
{
  printf("LoRa_handleDio0Rise");
  uint8_t irqFlags = LoRa_ReadRegister(REG_IRQ_FLAGS);
  // clear IRQ's
  LoRa_WriteRegister(REG_IRQ_FLAGS, irqFlags);
  if ((irqFlags & IRQ_PAYLOAD_CRC_ERROR_MASK) == 0)
  {
    // received a packet
    pLoRa_Attributes->packetIndex = 0;
    // read packet length
    int packetLength = pLoRa_Attributes->implicitHeaderMode ? LoRa_ReadRegister(REG_PAYLOAD_LENGTH) : LoRa_ReadRegister(REG_RX_NB_BYTES);
    // set FIFO address to current RX address
    LoRa_WriteRegister(REG_FIFO_ADDR_PTR, LoRa_ReadRegister(REG_FIFO_RX_CURRENT_ADDR));
    OnReceiveCallback(packetLength);
    // reset FIFO address
    LoRa_WriteRegister(REG_FIFO_ADDR_PTR, 0);
  }
}

void LoRa_HandleDio1Rise()
{
  uint8_t irqFlags = LoRa_ReadRegister(REG_IRQ_FLAGS);
  LoRa_WriteRegister(REG_IRQ_FLAGS, irqFlags);
  LoRa_WriteRegister(REG_FIFO_ADDR_PTR, 0);
}

/**************************************************/
